package com.xunyin.schedule;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.gson.Gson;
import com.xunyin.cache.TokenCache;
import com.xunyin.common.websocket.WsPool;
import com.xunyin.constant.SystemConfigConstants;
import com.xunyin.enums.AppFromEnum;
import com.xunyin.enums.OrderStatusEnum;
import com.xunyin.enums.StoreRoomStatusEnum;
import com.xunyin.event.TemplateBean;
import com.xunyin.event.TemplateEvent;
import com.xunyin.event.TemplateListenEnum;
import com.xunyin.modules.commontokentemp.domain.TCommonTokenTemp;
import com.xunyin.modules.commontokentemp.service.mapper.TCommonTokenTempMapper;
import com.xunyin.modules.device.domain.TDevice;
import com.xunyin.modules.device.domain.TDeviceLog;
import com.xunyin.modules.device.domain.TDevicePowerSet;
import com.xunyin.modules.device.domain.TDeviceVoiceSet;
import com.xunyin.modules.device.service.TDevicePowerSetService;
import com.xunyin.modules.device.service.TDeviceService;
import com.xunyin.modules.device.service.TDeviceVoiceSetService;
import com.xunyin.modules.device.service.mapper.TDeviceLogMapper;
import com.xunyin.modules.device.service.mapper.TDeviceMapper;
import com.xunyin.modules.mainpart.service.mapper.TMainPartMapper;
import com.xunyin.modules.membersuser.service.mapper.TMembersUserMapper;
import com.xunyin.modules.mp.service.WeixinPayShareBusService;
import com.xunyin.modules.mtstore.service.mapper.MtStoreRoomMapper;
import com.xunyin.modules.shareorder.bo.TeaOrderBo;
import com.xunyin.modules.shareorder.domain.TShareOrder;
import com.xunyin.modules.shareorder.service.mapper.TShareOrderMapper;
import com.xunyin.modules.store.domain.TStore;
import com.xunyin.modules.store.service.TStoreService;
import com.xunyin.modules.user.domain.SysXbAppUser;
import com.xunyin.modules.user.service.mapper.SysXbAppUserMapper;
import com.xunyin.nettyV.client.PubMsg;
import com.xunyin.utils.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 订单定时任务
 * 1、门禁授权码启用与失效
 * 2、电源远程控制
 * 3、短信提醒
 */
@Slf4j
@Configuration
@EnableScheduling
public class OrderSchedule {

    @Autowired
    TShareOrderMapper teaOrderMapper;

    @Autowired
    TDeviceLogMapper deviceLogMapper;

    @Autowired
    TCommonTokenTempMapper commonTokenTempMapper;

    @Autowired
    TMembersUserMapper teaMembersUserMapper;

    @Autowired
    TDeviceMapper deviceMapper;

    @Autowired
    TDeviceService tDeviceService;

    @Autowired
    TMainPartMapper sysMainMapper;

    @Autowired
    SysXbAppUserMapper sysXbAppUserMapper;

    @Autowired
    private TStoreService tStoreService;

    @Autowired
    private MtStoreRoomMapper mtStoreRoomMapper;

    /**
     * 硬件设备通断电设置
     */
    @Autowired
    private TDevicePowerSetService tDevicePowerSetService;

    /**
     * 硬件语音提示内容设置
     */
    @Autowired
    private TDeviceVoiceSetService tDeviceVoiceSetService;

    @Autowired
    private ApplicationEventPublisher publisher;

    @Autowired
    private TShareOrderMapper tShareOrderMapper;

    @Autowired
    private WeixinPayShareBusService weixinPayShareBusService;

    @Value("${tuya.url}")
    private String tuyaUrl;

    @Value("${tuya.client_id}")
    private String tuyaClientId;

    @Value("${tuya.client_secret}")
    private String tuyaClientSecret;

    /**
     * 60秒执行一次
     */
//    @Scheduled(fixedRate = 60000)
    private void fenzhang() {
        List<TShareOrder> list = tShareOrderMapper.getNotFzOrderList();
        for (TShareOrder tShareOrder: list) {
            try {
                String fz = weixinPayShareBusService.queryProfitSharing(tShareOrder, AppFromEnum.WECHAT.getValue());
                if ("PROCESSING".equals(fz)) {
                    tShareOrder.setFzFlag(0);
                    tShareOrder.setFzResult(fz);
                    tShareOrderMapper.updateById(tShareOrder);
                    continue;
                }
                if ("FINISHED".equals(fz)) {
                    tShareOrder.setFzFlag(1);
                    tShareOrder.setFzResult(fz);
                    tShareOrderMapper.updateById(tShareOrder);
                    continue;
                }
            } catch (Exception e) {
                log.error("查询分账有误, error={}", e.getMessage(), e);
            }
            try {
                String fz = weixinPayShareBusService.createProfitSharing(tShareOrder, AppFromEnum.WECHAT.getValue(), 1);
                if ("FINISHED".equals(fz)) {
                    tShareOrder.setFzFlag(1);
                }
                tShareOrder.setFzResult(fz);
                tShareOrderMapper.updateById(tShareOrder);
            } catch (Exception e) {
                log.error("分账有误, error={}", e.getMessage(), e);
            }
        }
    }

    /**
     * 1小时执行一次
     */
    //@Scheduled(fixedRate = 60 * 60 * 1000)
    private void PubTasks() throws MqttException {

        // 模板消息支付成功发布事件
        TemplateBean templateBean = TemplateBean.builder()
                .storeId(1)
                .orderNo("10102023062516134042001")
                .storeName("文娱共享茶室（杏林店")
                .storeRoomName("夏雨")
                .teaServerEndTime(new Date())
                .templateType(TemplateListenEnum.TYPE_10.getValue())
                .build();

        publisher.publishEvent(new TemplateEvent(this, templateBean));

/*        JSONObject reBasicDown = new JSONObject();
        reBasicDown.put("mac","00:0C:29:CA:E4:66");
        reBasicDown.put("relay",0);
        reBasicDown.put("time", DateUtils.parseDate2String(new Date(), "yyyy-MM-dd HH:mm:ss"));
        reBasicDown.put("reboot",1);
        reBasicDown.put("ip", MqConfig.ip);
        reBasicDown.put("port", MqConfig.port);
        PubMsg.publish(reBasicDown.toJSONString(), "client-id-0", "/dev/00:0C:29:CA:E4:66/basic/down");*/

    }

    /**
     * 1分钟执行一次
     */
//    @Scheduled(fixedRate = 60000)
    private void orderNoticeTasks() throws Exception {

        log.info("=====orderNoticeTasks=====");
        List<TeaOrderBo> orderScheduleData = teaOrderMapper.orderScheduleData();
        Integer orderStatus;
        long serverEndTime;
        long payTime;
        long now = (new Date()).getTime();
/*        if(!CollectionUtils.isEmpty(orderScheduleData)) {
            getAccessToken();
        }*/

        if (orderScheduleData != null && orderScheduleData.size() > 0) {
            log.info("=====orderScheduleData===== {}", JSONObject.toJSONString(orderScheduleData));
            //getAccessToken();
        }

        for (TeaOrderBo teaOrder : orderScheduleData) {

            orderStatus = teaOrder.getOrderStatus().intValue();
            if (teaOrder.getTeaServerEndTime() == null) {
                continue;
            }
            //payTime = teaOrder.getPayTime().getTime();
            serverEndTime = teaOrder.getTeaServerEndTime().getTime();

            String teaServerEndTime = DateUtil.parseDate2String(teaOrder.getTeaServerEndTime(), "yyyy-MM-dd HH:mm");
            if(teaServerEndTime.contains("00:00")){

                teaServerEndTime = teaServerEndTime.substring(0,11)+"24:00";

                serverEndTime = DateUtils.parseStrint2Date(teaServerEndTime, "yyyy-MM-dd HH:mm").getTime();

            }

            List<TDeviceVoiceSet> deviceVoiceSetList = tDeviceVoiceSetService.list();
            long serverEndTimeDiff = (serverEndTime - now) / 1000 / 60;
            log.info("{}：距离结束时间{}分钟", teaOrder.getStoreRoomName(), serverEndTimeDiff);

            // 看是否有相临时间续单，则不需要提醒
            Boolean isRemind = true;
            List<TeaOrderBo> repeatList = teaOrderMapper.orderListByParentOrderId(teaOrder.getId());
            if(repeatList!=null && repeatList.size() > 0){
                isRemind = false;
            }

            if(isRemind){

                if (OrderStatusEnum.IN_SERVICE.getIndex() == orderStatus) {

                    // 临近结束播报
                    TDeviceVoiceSet tDeviceVoiceSet = deviceVoiceSetList.get(1);

                    if (serverEndTimeDiff == tDeviceVoiceSet.getPromptTime()) {

                        // 小程序消息模板通过订单快结束，提醒续单
                        gzhOrderEndNotice(teaOrder);

                        sendNotice(teaOrder);

                        // tuya音箱语音提醒，订单快结束，提醒续单
                        String voiceText = "订单将在15分钟后到期！可通过小程序续单";
                        if(!"".equals(tDeviceVoiceSet.getPromptContent())){
                            voiceText = tDeviceVoiceSet.getPromptContent();
                            voiceText= voiceText.replace("{n}",tDeviceVoiceSet.getPromptTime()+"");
                        }
                        log.info("订单临近结束播报");
                        orderVoiceNotice(voiceText,teaOrder);


                    }
                }

                long serverEndDelayTimeDiff = (now - serverEndTime) / 1000 / 60;
                // 结束后播报
                TDeviceVoiceSet tDeviceVoiceSet = deviceVoiceSetList.get(2);
                /*if (serverEndDelayTimeDiff == tDeviceVoiceSet.getPromptTime()) {*/
                if (serverEndDelayTimeDiff == 0){
                    String voiceText = "您的订单已经结束";
                    if(!"".equals(tDeviceVoiceSet.getPromptContent())){
                        voiceText = tDeviceVoiceSet.getPromptContent();
                        voiceText= voiceText.replace("{n}",tDeviceVoiceSet.getPromptTime()+"");
                    }
                    log.info("订单结束播报");
                    orderVoiceNotice(voiceText,teaOrder);
                }

            }


            /*if(OrderStatusEnum.PAID.getIndex() == orderStatus) {
                long payTimeDiff = (now - payTime)/1000/60;
                log.info("{}：已支付{}分钟", teaOrder.getTeaChildName(), payTimeDiff);
                if(payTimeDiff == 1) {
                    try {
                        sendNewOrderNotice(teaOrder);
                    } catch (Exception e) {
                        log.error("orderNoticeTasks error -> {}", e);
                    }
                }
            }*/

        }
    }

    /**
     * 语音播报
     * @param voiceText
     * @param teaOrder
     * @throws Exception
     */
    private void orderVoiceNotice(String voiceText,TeaOrderBo teaOrder) throws Exception {
        // 调试中暂时注释
        // 根据设置的硬件方案,来控制不同品牌的下的硬件
        String hardwareProg = RedisUtil.get(SystemConfigConstants.XUNYIN_HARDWARE_PROG);
        // 默认选择涂鸦硬件方案
        if (StrUtil.isBlank(hardwareProg)) {
            sendVoiceNotice(voiceText, teaOrder);
        } else {

            // 自研硬件方案
            if (hardwareProg.equals("1")) {
                sendVoiceNoticeProg1(voiceText, teaOrder);
                // 涂鸦硬件方案
            } else {
                sendVoiceNotice(voiceText, teaOrder);
            }
        }
    }

    // 自研硬件发送语音指令
    private void sendVoiceNoticeProg1(String voiceText, TeaOrderBo teaOrder) throws Exception {
        TShareOrder updateTeaOrder = new TShareOrder();
        updateTeaOrder.setId(teaOrder.getId());
        // 待改善
        List<TDevice> devices = tDeviceService.getDeviceListByStoreRoomIdOrStoreId
                (null, teaOrder.getStoreRoomId(), 4);

        for (TDevice device : devices) {

/*            sendCommand(String mac, Integer commandType,
                    Integer switchFlag, String voiceText,
                    Integer type,Integer subPort,String serverIp)*/
            List relayList = new ArrayList();
            PubMsg.sendCommand(device.getMacAddr(), 3, 0, voiceText,device.getIsSub(),relayList,"");

        }
    }


    private void sendVoiceNotice(String voiceText, TeaOrderBo teaOrder) throws Exception {

        TShareOrder updateTeaOrder = new TShareOrder();
        updateTeaOrder.setId(teaOrder.getId());
        // 待改善
        List<TDevice> devices = tDeviceService.getDeviceListByStoreRoomIdOrStoreId
                (null, teaOrder.getStoreRoomId(), 3);

        for (TDevice device : devices) {

            String accessToken = TokenCache.getAccessTokenCache(tuyaClientId);
            String jsonParamStr = "{\"tts\": \"" + voiceText + "\",\"deviceId\": \"" + device.getDeviceNo() + "\"}";
            TDeviceLog deviceLog = new TDeviceLog();
            deviceLog.setDeviceNo(device.getDeviceNo());
            deviceLog.setCreateTime(new Date());
            deviceLog.setEvent((short) 2);
            deviceLog.setRemark("音箱语音提醒");

            String url = "/v1.0/aispeech/voice/push";
            Object result = RequestSignUtils.execute(accessToken, url, "POST", jsonParamStr, new HashMap<>());
            Gson gson = new Gson();
            String str = gson.toJson(result);
            log.info("音箱语音提醒:result={}", str);
            JSONObject resJson = JSONObject.parseObject(str);
            if (resJson.getBoolean("success")) {
                JSONObject resultJson = resJson.getJSONObject("result");
                if (resultJson.getBoolean("isSuccess")) {
                    deviceLog.setResultCode(200);
                    log.info("会客厅:{},音箱语音提醒:orderId={}, deviceNo={}", teaOrder.getStoreRoomName(), teaOrder.getId(), device.getDeviceNo());
                    log.info("/v1.0/aispeech/voice/push -> commands send success!{}", str);
                } else {
                    deviceLog.setResultCode(500);
                    log.error("/v1.0/aispeech/voice/push -> commands send error!{}", str);
                }
            } else {

                deviceLog.setResultCode(500);
                log.error("sendTempVoiceNotice -> commands send error!{},code={},msg={}", jsonParamStr, resJson.getString("code"), resJson.getString("msg"));

                String msg = resJson.getString("msg");
                if ("token invalid".equals(msg)) {
                    log.info("tuya_token invalid:{}", msg);
                    log.info("invalid_token:{}", TokenCache.getAccessTokenCache(tuyaClientId));
                    // 重新获取tuya token
                    getAccessTokenTask();
                    log.info("重新获取 tuya_token complete:{}", TokenCache.getAccessTokenCache(tuyaClientId));
                    // 重新音箱语音提醒
                    log.info("音箱语音提醒方法:{},orderId:{}", "sendVoiceNotice", teaOrder.getId());
                    sendVoiceNotice(voiceText, teaOrder);
                }
            }

            deviceLogMapper.insert(deviceLog);

        }
    }

    private void sendNewOrderNotice(TeaOrderBo teaOrder) {

        LambdaQueryWrapper<TCommonTokenTemp> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TCommonTokenTemp::getOfficialName, "wx6345a04c42ae10e3");
        TCommonTokenTemp commonTokenTemp = commonTokenTempMapper.selectOne(wrapper);
        String accessTokenStr = commonTokenTemp.getTokenCode();
        //组装url
        String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=ACCESS_TOKEN".replace("ACCESS_TOKEN", accessTokenStr);
        TStore tStore = tStoreService.getById(teaOrder.getStoreId());
        //JSONObject jsonObject = teaHouseDao.getTeaInfoById(teaOrder.getTeaHouseId());
        // 获取管理员手机号码
        String mamagerPhones = tStore.getRemark();
        LambdaQueryWrapper<SysXbAppUser> wrapperAppUser = new LambdaQueryWrapper<>();
        wrapperAppUser.eq(SysXbAppUser::getStatus, 1);
        wrapperAppUser.in(SysXbAppUser::getTelephone, mamagerPhones.split(","));
        List<SysXbAppUser> appUsers = sysXbAppUserMapper.selectList(wrapperAppUser);

        //
        String templateId = "469Qe6Uaj_Zk8Uj-zVwtqkDJHhkf2Bf-48X67rzzTKE";
        for (SysXbAppUser appUser : appUsers) {
/*            if(!"wxbc0747e6".equals(appUser.getWxAppId())) {
                continue;
            }*/

            String paramStr = "{\n" +
                    "  \"touser\": \"" + appUser.getAppId() + "\",\n" +
                    "  \"template_id\": \"" + templateId + "\",\n" +
                    "  \"data\": {\n" +
                    "      \"thing18\": {\n" +
                    "          \"value\": \"" + teaOrder.getStoreName() + ":" + teaOrder.getStoreRoomName() + "\"\n" +
                    "      },\n" +
                    "      \"thing5\": {\n" +
                    "          \"value\": \"新订单提醒\"\n" +
                    "      } \n" +
                    "  }\n" +
                    "}";

            log.info("sendNotice -> paramStr={}", paramStr);
            String result = HttpClientUtil.doPostJson(url, paramStr);
            log.info("sendNotice -> res={}", result);
        }

    }

    /**
     * 公众号消息-公众号消息用户下单成功通知保洁员
     * @param teaOrder
     */
    private void gzhOrderNewSuccessNotice(TeaOrderBo teaOrder){

        // 模板消息支付成功发布事件
        TemplateBean templateBean = TemplateBean.builder()
                .storeId(teaOrder.getStoreId())
                .storeName(teaOrder.getStoreName())
                .orderNo(teaOrder.getOrderNo())
                .orderMondey(teaOrder.getOrderMondey())
                .userPhone(teaOrder.getUserPhone())
                .storeRoomName(teaOrder.getStoreRoomName())
                .teaServerStartTime(teaOrder.getPayTime())
                //.teaServerStartTime(teaOrder.getTeaServerStartTime())
                .teaServerEndTime(teaOrder.getTeaServerEndTime())
                .templateType(TemplateListenEnum.TYPE_12.getValue())
                .build();

        publisher.publishEvent(new TemplateEvent(this, templateBean));

    }

    /**
     * 公众号消息-公众号消息订单结束提醒给保洁员通知
     * @param teaOrder
     */
    private void gzhOrderEndNotice(TeaOrderBo teaOrder){

        // 模板消息支付成功发布事件
        TemplateBean templateBean = TemplateBean.builder()
                .storeId(teaOrder.getStoreId())
                .storeName(teaOrder.getStoreName())
                .orderNo(teaOrder.getOrderNo())
                .storeRoomName(teaOrder.getStoreRoomName())
                .teaServerEndTime(teaOrder.getTeaServerEndTime())
                .templateType(TemplateListenEnum.TYPE_13.getValue())
                .build();

        publisher.publishEvent(new TemplateEvent(this, templateBean));
    }



    /**
     * 用户下单成功通知保洁员
     * @param teaOrder
     */
    private void orderNewSuccessNotice(TeaOrderBo teaOrder){

        // 模板消息支付成功发布事件
        TemplateBean templateBean = TemplateBean.builder()
                .storeId(teaOrder.getStoreId())
                .storeName(teaOrder.getStoreName())
                .orderNo(teaOrder.getOrderNo())
                .orderMondey(teaOrder.getOrderMondey())
                .userPhone(teaOrder.getUserPhone())
                .storeRoomName(teaOrder.getStoreRoomName())
                .teaServerStartTime(teaOrder.getTeaServerStartTime())
                .teaServerEndTime(teaOrder.getTeaServerEndTime())
                .templateType(TemplateListenEnum.TYPE_11.getValue())
                .build();

        publisher.publishEvent(new TemplateEvent(this, templateBean));

    }

    private void sendNotice(TeaOrderBo teaOrder) {

        // 模板消息支付成功发布事件
        TemplateBean templateBean = TemplateBean.builder()
                .storeId(teaOrder.getStoreId())
                .storeName(teaOrder.getStoreName())
                .orderNo(teaOrder.getOrderNo())
                .storeRoomName(teaOrder.getStoreRoomName())
                .teaServerEndTime(teaOrder.getTeaServerEndTime())
                .templateType(TemplateListenEnum.TYPE_10.getValue())
                .build();

        publisher.publishEvent(new TemplateEvent(this, templateBean));


/*        TMainPart sysMain = sysMainMapper.selectById(teaOrder.getMainId());
        String appId = sysMain.getAppId();
        LambdaQueryWrapper<TCommonTokenTemp> wrapper= new LambdaQueryWrapper<>();
        wrapper.eq(TCommonTokenTemp::getOfficialName,appId);
        TCommonTokenTemp commonTokenTemp =  commonTokenTempMapper.selectOne(wrapper);;
        String accessTokenStr = commonTokenTemp.getTokenCode();
        //组装url
        String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=ACCESS_TOKEN".replace("ACCESS_TOKEN", accessTokenStr);

        String templateId = "";

        //
        if("wx6345a04c42ae10e3".equals(appId)) {
            templateId = "xsD87o3kwfWSN_vMjEezLoOVy8q4HHhP9QNXmgwUSQ8";
        }

        String paramStr = "{\n" +
                "  \"touser\": \"" + teaOrder.getAppUserId() + "\",\n" +
                "  \"template_id\": \"" + templateId + "\",\n" +
                "  \"data\": {\n" +
                "      \"character_string1\": {\n" +
                "          \"value\": \"" + teaOrder.getOrderNo() + "\"\n" +
                "      },\n" +
                "      \"thing5\": {\n" +
                "          \"value\": \"包间：" + teaOrder.getStoreRoomName() + "\"\n" +
                "      },\n" +
                "      \"thing6\": {\n" +
                "          \"value\": \"订单将在15分钟后到期！可通过小程序续单哦\"\n" +
                "      } ,\n" +
                "      \"time4\": {\n" +
                "          \"value\": \"" + DateUtil.parseDate2String(teaOrder.getTeaServerEndTime(), "yyyy-MM-dd HH:mm") + "\"\n" +
                "      } \n" +
    *//*            "      \"phrase3\": {\n" +
                "          \"value\": \"即将结束\"\n" +
                "      }\n" +*//*
                "  }\n" +
                "}";

        log.info("sendNotice -> paramStr={}", paramStr);
        String result = HttpClientUtil.doPostJson(url, paramStr);
        log.info("sendNotice -> res={}", result);*/
    }

    private JSONObject sendCache = new JSONObject();

    /**
     * 15秒执行一次
     */
    @Scheduled(fixedRate = 15000)
    private void orderTasks() {

        List<TeaOrderBo> orderScheduleData = teaOrderMapper.orderScheduleData();
        Integer orderStatus;
        long serverStartTime;
        long serverEndTime;
        long createTime;
        long now = (new Date()).getTime();
/*        if(!CollectionUtils.isEmpty(orderScheduleData)) {
            getAccessToken();
        }*/

        // 电源、灯光、空调、麻将机、桌球锁球器,获取有效时间提前（分）
        List<TDevicePowerSet> devicePowerSetList = tDevicePowerSetService.list();

        for (TeaOrderBo teaOrder : orderScheduleData) {
            try {

                orderStatus = teaOrder.getOrderStatus().intValue();
                createTime = teaOrder.getCreateTime().getTime();

                // 未付款订单
                if (OrderStatusEnum.WAIT_PAY.getIndex() == orderStatus) {
                    waitPayOrder(now, createTime, teaOrder);
                    continue;
                }
                // 未付款订单
                if (OrderStatusEnum.CANCELLED.getIndex() == orderStatus || OrderStatusEnum.REFUNDED.getIndex() == orderStatus) {
                    continue;
                }

                serverStartTime = teaOrder.getTeaServerStartTime().getTime();
                serverEndTime = teaOrder.getTeaServerEndTime().getTime();
                String teaServerEndTime = DateUtil.parseDate2String(teaOrder.getTeaServerEndTime(), "yyyy-MM-dd HH:mm");
                if(teaServerEndTime.contains("00:00")){

                    teaServerEndTime = teaServerEndTime.substring(0,11)+"24:00";

                    serverEndTime = DateUtils.parseStrint2Date(teaServerEndTime, "yyyy-MM-dd HH:mm").getTime();

                }
                // 已付款订单
                if (OrderStatusEnum.PAID.getIndex() == orderStatus) {

                    long payTime = teaOrder.getPayTime().getTime();
                    long payTimeDiff = (now - payTime) / 1000 / 60;
                    log.info("{}：已支付{}分钟", teaOrder.getStoreRoomName(), payTimeDiff);
                    if (payTimeDiff == 0) {
                        if (sendCache.containsKey(teaOrder.getId().toString())) {
                            log.info("新订单消息已发送，无需重复发送");
                            return;
                        } else {

                            log.info("开始发送新订单消息");

                            // 用户下单成功通知保洁员
                            orderNewSuccessNotice(teaOrder);

                            gzhOrderNewSuccessNotice(teaOrder);

                            sendCache.put(teaOrder.getId().toString(), true);

                            try {
                                //sendNewOrderNotice(teaOrder);
                            } catch (Exception e) {
                                log.error("orderNoticeTasks error -> {}", e);
                            }

                        }
                    }

                    // 根据当前时间修改订单状态-订单开始前2分钟将订单状态改为服务中
                    long serverStartTimeDiff = (serverStartTime - now) / 1000 / 60;
                    log.info("{}：距离开始时间{}分钟", teaOrder.getStoreRoomName(), serverStartTimeDiff);
                    // 获取电源的提前几分钟开启，跟订单提前几分钟设置服务中同步
                    TDevicePowerSet tDevicePowerSet = devicePowerSetList.get(0);
                    if (serverStartTimeDiff <= tDevicePowerSet.getActiveAheadTime()) {

                        log.info("{} 订单生效：{}", new Date(), serverStartTimeDiff);

                        teaOrder.setOrderStatus(OrderStatusEnum.IN_SERVICE.getIndex());
                        TShareOrder tShareOrder = new TShareOrder();
                        BeanUtil.copyProperties(teaOrder, tShareOrder);
                        teaOrderMapper.updateById(tShareOrder);

                        // 设置订单对应的房间状态为“使用中”
                        // log.info("设置订单对应的{}房间状态为使用中,并更新房间服务结束时间{}"
                         mtStoreRoomMapper.updateStoreRoomStatus(
                                 StoreRoomStatusEnum.USE.getKey(),
                                 teaOrder.getTeaServerEndTime(),
                                 teaOrder.getStoreRoomId());

                        // 给小程序推送消息，首页刷新房间状态
                        // 如果订单已结束，房间状态实际为空闲中，如果用户停留在首页看到是使用中，自动刷新同步为空闲中
                        // 如果当前的时间有订单已开始，房间状态实际为使用中，如果用户停留在首页看到是空闲中，自动刷新同步为使用中
                        WsPool.sendMessageToAll("");

                    }
                }

//                // serviceStatus小于3，通电阶段
//                if (OrderStatusEnum.IN_SERVICE.getIndex() == orderStatus && teaOrder.getServiceStatus() < 3) {
//
//                    turnOnOper(serverStartTime,now,teaOrder,devicePowerSetList);
//
//                    turnOnOperAqara(serverStartTime,now,teaOrder,devicePowerSetList);
//
//
//                }
//
//                if (OrderStatusEnum.IN_SERVICE.getIndex() == orderStatus) {
//
//                    long serverStartTimeDiff = (serverStartTime - now) / 1000 / 60;
//                    // 待改善,获取包间订单的控制器设备配置
//                    List<TDevice> devices = tDeviceService.getDeviceListByStoreRoomIdOrStoreId
//                            (null, teaOrder.getStoreRoomId(), 4);
//
//                    // 自研硬件发送2灯光、3空调、4麻将机、5桌球锁球器开关 switchFlag 0 关 1 开
//                    turnOnDeviceOpt(serverStartTimeDiff,devices,devicePowerSetList);
//
//
//
//                }


                // 判断订单结束是否超过{n}分钟，如果是关闭包间电源
                if (OrderStatusEnum.COMPLETED.getIndex() == orderStatus && teaOrder.getServiceStatus() < 8) {

                    // 看是否有相临时间续单，则不需要断电
                    Boolean isOff = true;
                    List<TeaOrderBo> repeatList = teaOrderMapper.orderListByParentOrderId(teaOrder.getId());
                    if(repeatList!=null){
                        repeatList = repeatList.stream().filter(item -> item.getOrderStatus().intValue() == 2 || item.getOrderStatus().intValue() == 1).collect(Collectors.toList());
                    }
                    if(repeatList!=null && repeatList.size() > 0){
                        isOff = false;
                    }
/*                    for(TeaOrderBo teaOrderBo : repeatList){
                        // 当前订单结束时间与续单的开始时间
                        serverEndTime = teaOrder.getTeaServerEndTime().getTime();
                        long repeatStartTime = teaOrderBo.getTeaServerStartTime().getTime();
                        long repeatTimeDiff = (repeatStartTime - serverEndTime) / 1000 / 60;
                        // 表示有相临的订单
                        if (repeatTimeDiff <= 5) {
                            isOff = false;
                        }
                    }*/

//                    if(isOff){
//
//                        turnOffOper(serverEndTime,now,teaOrder,devicePowerSetList);
//
//                        turnOffOperAqara(serverEndTime,now,teaOrder,devicePowerSetList);
//
//                        // 设置订单对应的房间状态为“空闲中”
//                        log.info("设置订单对应的{}房间状态为空闲中", teaOrder.getStoreRoomId());
//                        mtStoreRoomMapper.updateStoreRoomStatus(StoreRoomStatusEnum.MODEL_TL.getKey(), teaOrder.getTeaServerEndTime(), teaOrder.getStoreRoomId());
//                        // 给小程序推送消息，首页刷新房间状态
////                        // 断电
////                        List relayList = new ArrayList<>();
////                        relayList.add(0);// 1表示电源开，0表示电源关
////                        relayList.add(device.getSubPort1Switch());
////                        relayList.add(device.getSubPort2Switch());
////                        relayList.add(device.getSubPort3Switch());
////
////                        PubMsg.sendCommand(device.getMacAddr(), 1, 0, "",device.getIsSub(), relayList,"");
//                        // 如果订单已结束，房间状态实际为空闲中，如果用户停留在首页看到是使用中，自动刷新同步为空闲中
//                        // 如果当前的时间有订单已开始，房间状态实际为使用中，如果用户停留在首页看到是空闲中，自动刷新同步为使用中
//                         WsPool.sendMessageToAll("");
//
//                    }
                    if (isOff) {
                        // 完结
                        mtStoreRoomMapper.updateStoreRoomStatus(StoreRoomStatusEnum.MODEL_TL.getKey(), teaOrder.getTeaServerEndTime(), teaOrder.getStoreRoomId());
                    } else {
                        // 续单
                        TeaOrderBo teaOrderBo = repeatList.get(0);
                        TDevice device = tDeviceService.getPowerDeviceByStoreRoomIdOrStoreId(teaOrderBo.getStoreId(), teaOrderBo.getStoreRoomId(), 2);
                        if (device != null) {
                            DeviceUtil1.userUnlock(device.getDeviceNo(), teaOrder.getTeaServerEndTime(), teaOrderBo.getTeaServerEndTime());
                        }
                    }
                }

                // 已付款订单或者已服务的订单根据订单结束时间设置订单状态
                if (OrderStatusEnum.PAID.getIndex() == orderStatus || OrderStatusEnum.IN_SERVICE.getIndex() == orderStatus) {

                    setOrderStatus(now, serverStartTime, serverEndTime, teaOrder);

                }

                // 如果是续单，在续单的服务时间内
                // 如果没打开电源，则打开电源（可以用包间的状态为空闲中，则表示上一个订单关闭电源的同时把对应的订单包间状态设置为空闲中）
                // 作为判断订单对应的包间电源是否打开
/*                if(teaOrder.getParentOrderId()>0){
                    // 当前时间是否在订单的服务时间段内
                    long serverStartTimeDiff = (serverStartTime - now) / 1000 / 60;
                    long serverEndTimeDiff = (now - serverEndTime) / 1000 / 60;
                    // 距离开始时间前2分钟,超出结束时间2分钟
                    if (serverStartTimeDiff <= 2 && serverEndTimeDiff < 2) {

                        // 查询订单对应的包间是否空闲中，如果是，则设置使用中，同时打开电源
                        MtStoreRoomVo mtStoreRoomVo = mtStoreRoomMapper.getStoreRoomInfor(teaOrder.getStoreRoomId());

                        // 如果为空闲中，则改订单为-使用中 同时 打开电源
                        if(mtStoreRoomVo.getStoreRoomStatus() == 0){

                            // 调试中暂时注释
                            // 根据设置的硬件方案,来控制不同品牌的下的硬件
                            String hardwareProg = RedisUtil.get(SystemConfigConstants.XUNYIN_HARDWARE_PROG);

                            turnOnElectricOper(hardwareProg,teaOrder);

                            // 设置订单对应的房间状态为“使用中”
                            log.info("设置订单对应的{}房间状态为使用中,并更新房间服务结束时间{}", teaOrder.getStoreRoomId(), teaOrder.getTeaServerEndTime());
                            mtStoreRoomMapper.updateStoreRoomStatus(StoreRoomStatusEnum.USE.getKey(), teaOrder.getTeaServerEndTime(), teaOrder.getStoreRoomId());

                        }
                    }
                }*/

            } catch (Exception e) {
                log.error("OrderSchedule.orderTasks error:{}", e);
            }
        }
    }

    /**
     * 打开 智能插座,获取有效时间提前（分）
     * @param serverStartTime
     * @param teaOrder
     * @throws Exception
     */
    private void turnOnOperAqara(long serverStartTime,long now,TeaOrderBo teaOrder,List<TDevicePowerSet> devicePowerSetList) throws Exception {

        // 待改善,获取包间订单的控制器设备配置-智能插座(Aqara)
        List<TDevice> devices = tDeviceService.getDeviceListByStoreRoomIdOrStoreId
                (null, teaOrder.getStoreRoomId(), 6);

        // 根据当前时间修改订单状态-订单开始前分钟打开电源
        long serverStartTimeDiff = (serverStartTime - now) / 1000 / 60;
        log.info("{}：距离开始时间{}分钟", teaOrder.getStoreRoomName(), serverStartTimeDiff);
        // 获取电源的提前几分钟开启,并发送指令给硬件，开启智能插座，跟订单提前几分钟设置服务中同步
        TDevicePowerSet tDevicePowerSet = devicePowerSetList.get(5);

        if (serverStartTimeDiff <= tDevicePowerSet.getActiveAheadTime()) {

            log.info("{} 打开智能插座：{}", new Date(), serverStartTimeDiff);

            for (TDevice device : devices) {

                RequestAqara.executeWriteResourceDevice(device.getDeviceNo(),"1");

            }

        }

    }

    /**
     * 关闭 智能开关,获取有效时间延后（分）
     * @param serverEndTime
     * @param teaOrder
     * @throws Exception
     */
    private void turnOffOperAqara(long serverEndTime,long now,TeaOrderBo teaOrder,List<TDevicePowerSet> devicePowerSetList) throws Exception {

        // 待改善,获取包间订单的控制器设备配置
        List<TDevice> devices = tDeviceService.getDeviceListByStoreRoomIdOrStoreId
                (null, teaOrder.getStoreRoomId(), 6);

        long serverEndTimeDiff = (now - serverEndTime) / 1000 / 60;

        // 获取电源的延后几分钟关闭,并发送指令给硬件
        TDevicePowerSet tDevicePowerSet = devicePowerSetList.get(5);
        if (serverEndTimeDiff < tDevicePowerSet.getActiveDelayTime()) {
            return;
        }

        for (TDevice device : devices) {
            RequestAqara.executeWriteResourceDevice(device.getDeviceNo(),"0");
        }

    }

    /**
     * 关闭 电源、灯光、空调、麻将机、桌球锁球器,获取有效时间延后（分）
     * @param serverEndTime
     * @param teaOrder
     * @throws Exception
     */
    private void turnOffOper(long serverEndTime,long now,TeaOrderBo teaOrder,List<TDevicePowerSet> devicePowerSetList) throws Exception {

        // 语音结束后播报
        // List deviceVoiceSetList = tDeviceVoiceSetService.list();

        // 待改善,获取包间订单的控制器设备配置
        List<TDevice> devices = tDeviceService.getDeviceListByStoreRoomIdOrStoreId
                (null, teaOrder.getStoreRoomId(), 4);

        long serverEndTimeDiff = (now - serverEndTime) / 1000 / 60;

        // 自研硬件发送2灯光、3空调、4麻将机、5桌球锁球器开关 switchFlag 0 关 1 开
        turnOffDeviceOpt(serverEndTimeDiff,devices,devicePowerSetList);

        // log.info("超出结束时间{}分钟", serverEndTimeDiff);
        // 获取电源的延后几分钟关闭,并发送指令给硬件
        TDevicePowerSet tDevicePowerSet = devicePowerSetList.get(0);
        if (serverEndTimeDiff < tDevicePowerSet.getActiveDelayTime()) {
            return;
        }

        // 调试中暂时注释
        // 根据设置的硬件方案,来控制不同品牌的下的硬件
        String hardwareProg = RedisUtil.get(SystemConfigConstants.XUNYIN_HARDWARE_PROG);
        // 默认选择涂鸦硬件方案
        if (StrUtil.isBlank(hardwareProg)) {
            turnOffElectric(now, serverEndTime, teaOrder);
        } else {
            // 自研硬件方案
            if (hardwareProg.equals("1")) {
                turnOffElectricProg1(now, serverEndTime, teaOrder,devices);
            // 涂鸦硬件方案
            } else {
                turnOffElectric(now, serverEndTime, teaOrder);
            }
        }
    }

    /**
     * 打开 电源、灯光、空调、麻将机、桌球锁球器,获取有效时间提前（分）
     * @param serverStartTime
     * @param teaOrder
     * @throws Exception
     */
    private void turnOnOper(long serverStartTime,long now,TeaOrderBo teaOrder,List<TDevicePowerSet> devicePowerSetList) throws Exception {

        // 待改善,获取包间订单的控制器设备配置
        List<TDevice> devices = tDeviceService.getDeviceListByStoreRoomIdOrStoreId
                (null, teaOrder.getStoreRoomId(), 4);

        // 根据当前时间修改订单状态-订单开始前分钟打开电源
        long serverStartTimeDiff = (serverStartTime - now) / 1000 / 60;
        log.info("{}：距离开始时间{}分钟", teaOrder.getStoreRoomName(), serverStartTimeDiff);
        // 获取电源的提前几分钟开启,并发送指令给硬件，开启包间电源，跟订单提前几分钟设置服务中同步
        TDevicePowerSet tDevicePowerSet = devicePowerSetList.get(0);

        if (serverStartTimeDiff <= tDevicePowerSet.getActiveAheadTime()) {

            log.info("{} 打开电源：{}", new Date(), serverStartTimeDiff);

            // 调试中暂时注释
            // 根据设置的硬件方案,来控制不同品牌的下的硬件
            String hardwareProg = RedisUtil.get(SystemConfigConstants.XUNYIN_HARDWARE_PROG);

            // turnOnElectricOper(hardwareProg,teaOrder);
            // 默认选择涂鸦硬件方案
            if (StrUtil.isBlank(hardwareProg)) {

                turnOnElectric(teaOrder);

            } else {

                // 自研硬件方案
                if (hardwareProg.equals("1")) {

                    turnOnElectricProg1(devices,teaOrder);

                // 涂鸦硬件方案
                } else {

                    turnOnElectric(teaOrder);
                }
            }

            // 设置订单对应的房间状态为“使用中”
            // log.info("设置订单对应的{}房间状态为使用中,并更新房间服务结束时间{}", teaOrder.getStoreRoomId(), teaOrder.getTeaServerEndTime());
            // mtStoreRoomMapper.updateStoreRoomStatus(StoreRoomStatusEnum.USE.getKey(), teaOrder.getTeaServerEndTime(), teaOrder.getStoreRoomId());
        }

    }

    private void setOrderStatus(long now, long serverStartTime, long serverEndTime, TeaOrderBo teaOrder) {

        // 当前时间大于开始时间且小于订单结束时间，
        if (serverStartTime < now && now < serverEndTime && !CommonConst.ORDER_SERVICE.equals(teaOrder.getOrderStatus())) {

            teaOrder.setOrderStatus(CommonConst.ORDER_SERVICE);
            teaOrder.setUpdateTime(new Date());
            TShareOrder tShareOrder = new TShareOrder();
            BeanUtil.copyProperties(teaOrder, tShareOrder);
            teaOrderMapper.updateById(tShareOrder);
            //teaOrderMapper.updateByPrimaryKeyWithBLOBs(teaOrder);

        // 当前时间大于结束时间
        } else if (serverEndTime < now) {

            teaOrder.setOrderStatus(CommonConst.ORDER_SUCCESS);
            teaOrder.setUpdateTime(new Date());
            TShareOrder tShareOrder = new TShareOrder();
            BeanUtil.copyProperties(teaOrder, tShareOrder);
            teaOrderMapper.updateById(tShareOrder);

            //teaOrderMapper.updateByPrimaryKeyWithBLOBs(teaOrder);
        }
    }

    /**
     * 自研硬件发送2灯光、3空调、4麻将机、5桌球锁球器开关 switchFlag 0 关  1 开
     *
     * @throws Exception
     */
    public void turnOnDeviceOpt(long serverStartTimeDiff,List<TDevice> devices,
                                List<TDevicePowerSet> devicePowerSetList) throws MqttException {

        // 获取订单对应的控制器设备配置
        // 判断是否支持分控
        // 如果支持分控，获取端口1、端口2、端口3 配置对应的设备选项（1电源、2灯光、3空调、4麻将机、5桌球锁球器）
        // 根据设备选项，获取有效时间提前（分）
        // 发送设备选项对应端口1、端口2、端口3指令,subPort[0,0,0,0]
        TDevicePowerSet tDevicePowerSet = null;

        for (TDevice device : devices) {

            // 表示支持分控
            if(device.getIsSub() == 1){

                log.info("支持分控硬件："+device.getDeviceName()+"-"+device.getMacAddr()+"-"+device.getIsSub());

                List relayList = new ArrayList<>();
                relayList.add(device.getSubPort0Switch());
                relayList.add(device.getSubPort1Switch());
                relayList.add(device.getSubPort2Switch());
                relayList.add(device.getSubPort3Switch());
                // 如果是服务中,小于等于电源开启时间，但电源是关的，则把电源开启
                tDevicePowerSet = devicePowerSetList.get(0);
                Integer subPort0Switch = device.getSubPort0Switch();
                if (serverStartTimeDiff <= tDevicePowerSet.getActiveAheadTime() && subPort0Switch==0) {
                    relayList.set(0,1);
                    PubMsg.sendCommand(device.getMacAddr(), 1, 1, "",device.getIsSub(),relayList,"");
                    deviceMapper.updateSubPort0SwitchStatus(1,device.getId());
                }

                Integer subPort1 = device.getSubPort1();
                Integer subPort1Switch = device.getSubPort1Switch();
                if(subPort1!=null && subPort1>0){
                    // 对应设备选项的有效时间提前（分）
                    tDevicePowerSet = devicePowerSetList.get(1);
                    if (serverStartTimeDiff <= tDevicePowerSet.getActiveAheadTime() && subPort1Switch==0) {
                        // 发送分控指令 [0,1,0,0]
                        log.info("发送分控指令-端口1-subPort1："+device.getMacAddr()+"-"+device.getIsSub()+"-"+subPort1+"_switchFlag:"+1);
                        relayList.set(1,1);
                        PubMsg.sendCommand(device.getMacAddr(), 1, 1, "",device.getIsSub(),relayList,"");
                        //relayList.set(1,1);
/*                      device.setSubPort1Switch(1);
                        LambdaQueryWrapper<TDevice> wrapper = new LambdaQueryWrapper<>();
                        wrapper.eq(TDevice::getId, device.getId());
                        deviceMapper.update(device,wrapper);*/
                        deviceMapper.updateSubPort1SwitchStatus(1,device.getId());
                    }

                }

                Integer subPort2 = device.getSubPort2();
                Integer subPort2Switch = device.getSubPort2Switch();
                if(subPort2!=null && subPort2>0){
                    // 对应设备选项的有效时间提前（分）
                    tDevicePowerSet = devicePowerSetList.get(2);
                    if (serverStartTimeDiff <= tDevicePowerSet.getActiveAheadTime() && subPort2Switch==0) {
                        // 发送分控指令 [0,0,1,0]
                        log.info("发送分控指令-端口2-subPort2："+device.getMacAddr()+"-"+device.getIsSub()+"-"+subPort2+"_switchFlag:"+1);
                        relayList.set(2,1);
                        PubMsg.sendCommand(device.getMacAddr(), 1, 1, "",device.getIsSub(),relayList,"");
                        //relayList.set(2,1);
                        deviceMapper.updateSubPort2SwitchStatus(1,device.getId());
                    }

                }

                Integer subPort3 = device.getSubPort3();
                Integer subPort3Switch = device.getSubPort3Switch();
                if(subPort3!=null && subPort3>0){
                    // 对应设备选项的有效时间提前（分）
                    tDevicePowerSet = devicePowerSetList.get(3);
                    if (serverStartTimeDiff <= tDevicePowerSet.getActiveAheadTime() && subPort3Switch==0) {
                        // 发送分控指令 [0,0,0,1]
                        log.info("发送分控指令-端口3-subPort3："+device.getMacAddr()+"-"+device.getIsSub()+"-"+subPort3+"_switchFlag:"+1);
                        relayList.set(3,1);
                        PubMsg.sendCommand(device.getMacAddr(), 1, 1, "",device.getIsSub(),relayList,"");
                        //relayList.set(3,1);
                        deviceMapper.updateSubPort3SwitchStatus(1,device.getId());

                    }
                }

            }
        }
    }

    /**
     * 自研硬件发送2灯光、3空调、4麻将机、5桌球锁球器开关 switchFlag 0 关   1 开
     *
     * @throws Exception
     */
    public void turnOffDeviceOpt(long serverEndTimeDiff,List<TDevice> devices,
                                List<TDevicePowerSet> devicePowerSetList) throws MqttException {

        // 获取订单对应的控制器设备配置
        // 判断是否支持分控
        // 如果支持分控，获取端口1、端口2、端口3 配置对应的设备选项（1电源、2灯光、3空调、4麻将机、5桌球锁球器）
        // 根据设备选项，获取有效时间提前（分）
        // 发送设备选项对应端口1、端口2、端口3指令,subPort[0,0,0,0]

        TDevicePowerSet tDevicePowerSet = null;
        for (TDevice device : devices) {

            // 表示支持分控
            if(device.getIsSub() == 1){

                List relayList = new ArrayList<>();
                relayList.add(device.getSubPort0Switch()); // 1表示电源开，0表示电源关
                relayList.add(device.getSubPort1Switch());
                relayList.add(device.getSubPort2Switch());
                relayList.add(device.getSubPort3Switch());

                Integer subPort1 = device.getSubPort1();
                Integer subPort1Switch = device.getSubPort1Switch();
                if(subPort1!=null && subPort1>0){
                    // 对应设备选项的有效时间延后（分）
                    tDevicePowerSet = devicePowerSetList.get(1);
                    if (serverEndTimeDiff > tDevicePowerSet.getActiveDelayTime() && subPort1Switch==1) {
                        // 发送分控指令 [0,1,0,0]
                        log.info("发送分控指令-端口1-subPort1："+device.getMacAddr()+"-"+device.getIsSub()+"-"+subPort1+"_switchFlag:"+0);
                        relayList.set(1,0);
                        PubMsg.sendCommand(device.getMacAddr(), 1, 0, "",device.getIsSub(),relayList,"");
                        deviceMapper.updateSubPort1SwitchStatus(0,device.getId());
                    }
                }

                Integer subPort2 = device.getSubPort2();
                Integer subPort2Switch = device.getSubPort2Switch();
                if(subPort2!=null && subPort2>0){
                    // 对应设备选项的有效时间延后（分）
                    tDevicePowerSet = devicePowerSetList.get(2);
                    if (serverEndTimeDiff > tDevicePowerSet.getActiveDelayTime() && subPort2Switch==1) {
                        // 发送分控指令 [0,0,1,0]
                        log.info("发送分控指令-端口2-subPort2："+device.getMacAddr()+"-"+device.getIsSub()+"-"+subPort2+"_switchFlag:"+0);
                        relayList.set(2,0);
                        PubMsg.sendCommand(device.getMacAddr(), 1, 0, "",device.getIsSub(),relayList,"");
                        deviceMapper.updateSubPort2SwitchStatus(0,device.getId());
                    }
                }

                Integer subPort3 = device.getSubPort3();
                Integer subPort3Switch = device.getSubPort3Switch();
                if(subPort3!=null && subPort3>0){
                    // 对应设备选项的有效时间延后（分）
                    tDevicePowerSet = devicePowerSetList.get(3);
                    if (serverEndTimeDiff > tDevicePowerSet.getActiveDelayTime() && subPort3Switch==1) {
                        // 发送分控指令 [0,0,0,1]
                        log.info("发送分控指令-端口3-subPort3："+device.getMacAddr()+"-"+device.getIsSub()+"-"+subPort3+"_switchFlag:"+0);
                        relayList.set(3,0);
                        PubMsg.sendCommand(device.getMacAddr(), 1, 0, "",device.getIsSub(),relayList,"");
                        deviceMapper.updateSubPort3SwitchStatus(0,device.getId());
                    }
                }

            }
        }
    }

    /**
     * 自研硬件发送电源开关 switchFlag 0 关   1 开
     *
     * @param teaOrder
     * @throws Exception
     */
    private void turnOnElectricProg1(List<TDevice> devices,TeaOrderBo teaOrder) throws Exception {

        Boolean allSuccess = true;
        int successCount = 0;
        for (TDevice device : devices) {


            List relayList = new ArrayList<>();
            relayList.add(1);// 1表示电源开，0表示电源关
            relayList.add(device.getSubPort1Switch());
            relayList.add(device.getSubPort2Switch());
            relayList.add(device.getSubPort3Switch());
            relayList.set(0,1);
            PubMsg.sendCommand(device.getMacAddr(), 1, 1, "",device.getIsSub(),relayList,"");
            deviceMapper.updateSubPort0SwitchStatus(1,device.getId());

            successCount++;
            TDeviceLog deviceLog = new TDeviceLog();
            deviceLog.setDeviceNo(device.getDeviceNo());
            deviceLog.setCreateTime(new Date());
            // 通电
            deviceLog.setEvent((short) 1);
            deviceLog.setRemark("通电");
            deviceLog.setResultCode(200);
            deviceLogMapper.insert(deviceLog);

        }

        if (allSuccess) {
            log.info("success 全部通电成功");
            teaOrder.setServiceStatus(3);
            TShareOrder tShareOrder = new TShareOrder();
            BeanUtil.copyProperties(teaOrder, tShareOrder);
            teaOrderMapper.updateById(tShareOrder);
            //teaOrderMapper.updateByPrimaryKeySelective(teaOrder);
        } else if (!allSuccess && successCount > 0) {
            log.error("部分通电成功");
            if (teaOrder.getServiceStatus() == -2) {
                teaOrder.setServiceStatus(1);
            } else if (teaOrder.getServiceStatus() == 0) {
                teaOrder.setServiceStatus(1);
            } else if (teaOrder.getServiceStatus() == 1) {
                teaOrder.setServiceStatus(2);
            } else if (teaOrder.getServiceStatus() == 2) {
                teaOrder.setServiceStatus(3);
            }
            TShareOrder tShareOrder = new TShareOrder();
            BeanUtil.copyProperties(teaOrder, tShareOrder);
            teaOrderMapper.updateById(tShareOrder);
            // teaOrderMapper.updateByPrimaryKeySelective(teaOrder);
        } else if (successCount == 0) {
            log.error("全部通电失败");
            if (teaOrder.getServiceStatus() == 0 || teaOrder.getServiceStatus() == 1) {
                teaOrder.setServiceStatus(2);
            } else {
                teaOrder.setServiceStatus(3);
            }
            TShareOrder tShareOrder = new TShareOrder();
            BeanUtil.copyProperties(teaOrder, tShareOrder);
            teaOrderMapper.updateById(tShareOrder);
            // teaOrderMapper.updateByPrimaryKeySelective(teaOrder);
        }

    }

    private void turnOnElectric(TeaOrderBo teaOrder) throws Exception {

        // 待改善
        List<TDevice> devices = tDeviceService.getDeviceListByStoreRoomIdOrStoreId
                (null, teaOrder.getStoreRoomId(), 2);

        Boolean allSuccess = true;
        int successCount = 0;
        for (TDevice device : devices) {
            if (device.getDeviceType() == 0) {
                //门禁，不发指令
                continue;
            }
            Date date = new Date();
            String t = String.valueOf(date.getTime());
            Map<String, String> headerParam = new HashMap<>();
            String accessToken = TokenCache.getAccessTokenCache(tuyaClientId);
            headerParam.put("client_id", tuyaClientId);
            headerParam.put("access_token", accessToken);
            headerParam.put("sign", SignUtil.HMACSHA256(tuyaClientId + accessToken + t, tuyaClientSecret));
            headerParam.put("t", t);
            headerParam.put("sign_method", "HMAC-SHA256");
            headerParam.put("Content-Type", "application/json");
            String switch_1 = "switch_1";
            String jsonParamStr = "{\"commands\":[{\"code\": \"" + switch_1 + "\",\"value\":true}]}";
            Gson gson = new Gson();
            String busPath = "/v1.0/iot-03/devices/" + device.getDeviceNo() + "/commands";
            Object result = RequestSignUtils.execute(accessToken, busPath, "POST", jsonParamStr, new HashMap<>());
            String res = gson.toJson(result);
            log.info("打开电源发送指令返回结果：{}", res);
            if (StringUtils.isEmpty(res)) {
                continue;
            }
            TDeviceLog deviceLog = new TDeviceLog();
            deviceLog.setDeviceNo(device.getDeviceNo());
            deviceLog.setCreateTime(new Date());
            // 通电
            deviceLog.setEvent((short) 1);
            deviceLog.setRemark("通电");
            JSONObject resJson = JSONObject.parseObject(res);
            if (resJson.getBoolean("success")) {
                if (resJson.getBoolean("result")) {
                    successCount++;
                    deviceLog.setResultCode(200);
                    log.info("会客厅:{},通电成功:orderId={}, deviceNo={}", teaOrder.getStoreRoomName(), teaOrder.getId(), device.getDeviceNo());
                    log.info("orderTasks -> commands send success!{}", jsonParamStr);
                } else {
                    allSuccess = false;
                    deviceLog.setResultCode(500);
                    log.error("orderTasks -> commands send error!{}", jsonParamStr);
                }
            } else {


                allSuccess = false;
                deviceLog.setResultCode(500);
                log.error("orderTasks -> commands send error!{}", jsonParamStr);

                String msg = resJson.getString("msg");
                if ("token invalid".equals(msg)) {
                    log.info("tuya_token invalid:{}", msg);
                    log.info("invalid_token:{}", TokenCache.getAccessTokenCache(tuyaClientId));
                    // 重新获取tuya token
                    getAccessTokenTask();
                    log.info("重新获取 tuya_token complete:{}", TokenCache.getAccessTokenCache(tuyaClientId));
                    // 重新打开电源
                    log.info("重新打开电源方法:{}", "turnOnElectric");
                    turnOnElectric(teaOrder);
                }

            }

            deviceLogMapper.insert(deviceLog);
        }

        if (allSuccess) {
            log.info("success 全部通电成功");
            teaOrder.setServiceStatus(3);
            TShareOrder tShareOrder = new TShareOrder();
            BeanUtil.copyProperties(teaOrder, tShareOrder);
            teaOrderMapper.updateById(tShareOrder);
            //teaOrderMapper.updateByPrimaryKeySelective(teaOrder);
        } else if (!allSuccess && successCount > 0) {
            log.error("部分通电成功");
            if (teaOrder.getServiceStatus() == -2) {
                teaOrder.setServiceStatus(1);
            } else if (teaOrder.getServiceStatus() == 0) {
                teaOrder.setServiceStatus(1);
            } else if (teaOrder.getServiceStatus() == 1) {
                teaOrder.setServiceStatus(2);
            } else if (teaOrder.getServiceStatus() == 2) {
                teaOrder.setServiceStatus(3);
            }
            TShareOrder tShareOrder = new TShareOrder();
            BeanUtil.copyProperties(teaOrder, tShareOrder);
            teaOrderMapper.updateById(tShareOrder);
            // teaOrderMapper.updateByPrimaryKeySelective(teaOrder);
        } else if (successCount == 0) {
            log.error("全部通电失败");
            if (teaOrder.getServiceStatus() == 0 || teaOrder.getServiceStatus() == 1) {
                teaOrder.setServiceStatus(2);
            } else {
                teaOrder.setServiceStatus(3);
            }
            TShareOrder tShareOrder = new TShareOrder();
            BeanUtil.copyProperties(teaOrder, tShareOrder);
            teaOrderMapper.updateById(tShareOrder);
            // teaOrderMapper.updateByPrimaryKeySelective(teaOrder);
        }

    }

    /**
     * 自研硬件发送电源开关 switchFlag 0 关   1 开
     *
     * @param teaOrder
     * @throws Exception
     */
    private void turnOffElectricProg1(long now, long serverEndTime, TeaOrderBo teaOrder,List<TDevice> devices) throws Exception {

/*        long serverEndTimeDiff = (now - serverEndTime) / 1000 / 60;

        // log.info("超出结束时间{}分钟", serverEndTimeDiff);
        if (serverEndTimeDiff < 2) {
            return;
        }*/

        TShareOrder updateTeaOrder = new TShareOrder();
        updateTeaOrder.setId(teaOrder.getId());

        int count = teaOrderMapper.countTeaHouseOrder(teaOrder.getId());
        if (count > 0) {
            log.info("会客厅{}有续单，不关闭电源!", teaOrder.getStoreRoomName());
            updateTeaOrder.setServiceStatus(8);
            teaOrderMapper.updateById(updateTeaOrder);
            //teaOrderMapper.updateByPrimaryKeySelective(updateTeaOrder);
            return;
        }

        Boolean allSuccess = true;
        int successCount = 0;
        for (TDevice device : devices) {

            List relayList = new ArrayList<>();
            relayList.add(0);// 1表示电源开，0表示电源关
            relayList.add(device.getSubPort1Switch());
            relayList.add(device.getSubPort2Switch());
            relayList.add(device.getSubPort3Switch());

            PubMsg.sendCommand(device.getMacAddr(), 1, 0, "",device.getIsSub(), relayList,"");
            deviceMapper.updateSubPort0SwitchStatus(0,device.getId());

            successCount++;
            TDeviceLog deviceLog = new TDeviceLog();
            deviceLog.setDeviceNo(device.getDeviceNo());
            deviceLog.setCreateTime(new Date());

            // 断电
            deviceLog.setEvent((short) 2);
            deviceLog.setRemark("断电");
            deviceLog.setResultCode(200);
            deviceLogMapper.insert(deviceLog);

        }

        if (allSuccess) {
            //log.info("success 全部断电成功");
            teaOrder.setServiceStatus(8);
            TShareOrder tShareOrder = new TShareOrder();
            BeanUtil.copyProperties(teaOrder, tShareOrder);
            teaOrderMapper.updateById(tShareOrder);
            //teaOrderMapper.updateByPrimaryKeySelective(teaOrder);
        } else if (!allSuccess && successCount > 0) {
            //log.error("部分断电成功");
            if (teaOrder.getServiceStatus() == 3 || teaOrder.getServiceStatus() == 5) {
                teaOrder.setServiceStatus(6);
            } else if (teaOrder.getServiceStatus() == 6) {
                teaOrder.setServiceStatus(7);
            } else if (teaOrder.getServiceStatus() == 7) {
                teaOrder.setServiceStatus(8);
            } else {
                teaOrder.setServiceStatus(6);
            }
            TShareOrder tShareOrder = new TShareOrder();
            BeanUtil.copyProperties(teaOrder, tShareOrder);
            teaOrderMapper.updateById(tShareOrder);
            //teaOrderMapper.updateByPrimaryKeySelective(teaOrder);
        } else if (successCount == 0) {
            log.error("全部断电失败");
            if (teaOrder.getServiceStatus() == 3 || teaOrder.getServiceStatus() == 5 || teaOrder.getServiceStatus() == 6) {
                teaOrder.setServiceStatus(7);
            } else {
                teaOrder.setServiceStatus(8);
            }
            TShareOrder tShareOrder = new TShareOrder();
            BeanUtil.copyProperties(teaOrder, tShareOrder);
            teaOrderMapper.updateById(tShareOrder);
            //teaOrderMapper.updateByPrimaryKeySelective(teaOrder);
        }
    }

    private void turnOffElectric(long now, long serverEndTime, TeaOrderBo teaOrder) throws Exception {
/*        long serverEndTimeDiff = (now - serverEndTime) / 1000 / 60;

        //log.info("超出结束时间{}分钟", serverEndTimeDiff);
        if (serverEndTimeDiff < 2) {
            return;
        }*/

        TShareOrder updateTeaOrder = new TShareOrder();
        updateTeaOrder.setId(teaOrder.getId());

        //JSONObject param = new JSONObject();
        //param.put("parentOrderId", teaOrder.getId());
        int count = teaOrderMapper.countTeaHouseOrder(teaOrder.getId());
        if (count > 0) {
            log.info("会客厅{}有续单，不关闭电源!", teaOrder.getStoreRoomName());
            updateTeaOrder.setServiceStatus(8);
            teaOrderMapper.updateById(updateTeaOrder);
            //teaOrderMapper.updateByPrimaryKeySelective(updateTeaOrder);
            return;
        }
        // 待改善
        List<TDevice> devices = tDeviceService.getDeviceListByStoreRoomIdOrStoreId
                (null, teaOrder.getStoreRoomId(), 2);
        //List<TDevice> devices = tDeviceService.getDoorListByStoreRoomIdOrStoreId(null,teaOrder.getStoreRoomId());
        //List<Device> devices = deviceMapper.getListByTeaHouseId(teaOrder.getTeaChildId());
        Boolean allSuccess = true;
        int successCount = 0;
        for (TDevice device : devices) {
            if (device.getDeviceType() == 0) {
                //大门设备，不发指令
                continue;
            }

            Date date = new Date();
            String t = String.valueOf(date.getTime());
            Map<String, String> headerParam = new HashMap<>();
            String accessToken = TokenCache.getAccessTokenCache(tuyaClientId);
            headerParam.put("client_id", tuyaClientId);
            headerParam.put("access_token", accessToken);
            headerParam.put("sign", SignUtil.HMACSHA256(tuyaClientId + accessToken + t, tuyaClientSecret));
            headerParam.put("t", t);
            headerParam.put("sign_method", "HMAC-SHA256");
            headerParam.put("Content-Type", "application/json");
            String switch_1 = "switch_1";
            String jsonParamStr = "{\"commands\":[{\"code\": \"" + switch_1 + "\",\"value\":false}]}";
            Gson gson = new Gson();
            String busPath = "/v1.0/iot-03/devices/" + device.getDeviceNo() + "/commands";
            Object result = RequestSignUtils.execute(accessToken, busPath, "POST", jsonParamStr, new HashMap<>());
            String res = gson.toJson(result);
            log.info("关闭电源发送指令返回结果：{}", res);

            if (StringUtils.isEmpty(res)) {
                continue;
            }

            TDeviceLog deviceLog = new TDeviceLog();
            deviceLog.setDeviceNo(device.getDeviceNo());
            deviceLog.setCreateTime(new Date());

            // 断电
            deviceLog.setEvent((short) 2);
            deviceLog.setRemark("断电");
            JSONObject resJson = JSONObject.parseObject(res);
            if (resJson.getBoolean("success")) {
                if (resJson.getBoolean("result")) {
                    successCount++;
                    deviceLog.setResultCode(200);
                    log.info("会客厅:{},通电断电:orderId={}, deviceNo={}", teaOrder.getStoreRoomName(), teaOrder.getId(), device.getDeviceNo());
                    log.info("orderTasks -> commands send success!{}", jsonParamStr);
                } else {
                    allSuccess = false;
                    deviceLog.setResultCode(500);
                    log.error("orderTasks -> commands send error!{}", jsonParamStr);
                }
            } else {

                allSuccess = false;
                deviceLog.setResultCode(500);
                log.error("orderTasks -> commands send error!{}", jsonParamStr);

                String msg = resJson.getString("msg");
                if ("token invalid".equals(msg)) {
                    log.info("tuya_token invalid:{}", msg);
                    log.info("invalid_token:{}", TokenCache.getAccessTokenCache(tuyaClientId));
                    // 重新获取tuya token
                    getAccessTokenTask();
                    log.info("重新获取 tuya_token complete:{}", TokenCache.getAccessTokenCache(tuyaClientId));
                    // 重新关闭电源
                    log.info("重新关闭电源方法:{}", "turnOffElectric");
                    turnOffElectric(now, serverEndTime, teaOrder);
                }
            }

            deviceLogMapper.insert(deviceLog);
        }

        if (allSuccess) {
            //log.info("success 全部断电成功");
            teaOrder.setServiceStatus(8);
            TShareOrder tShareOrder = new TShareOrder();
            BeanUtil.copyProperties(teaOrder, tShareOrder);
            teaOrderMapper.updateById(tShareOrder);
            //teaOrderMapper.updateByPrimaryKeySelective(teaOrder);
        } else if (!allSuccess && successCount > 0) {
            //log.error("部分断电成功");
            if (teaOrder.getServiceStatus() == 3 || teaOrder.getServiceStatus() == 5) {
                teaOrder.setServiceStatus(6);
            } else if (teaOrder.getServiceStatus() == 6) {
                teaOrder.setServiceStatus(7);
            } else if (teaOrder.getServiceStatus() == 7) {
                teaOrder.setServiceStatus(8);
            } else {
                teaOrder.setServiceStatus(6);
            }
            TShareOrder tShareOrder = new TShareOrder();
            BeanUtil.copyProperties(teaOrder, tShareOrder);
            teaOrderMapper.updateById(tShareOrder);
            //teaOrderMapper.updateByPrimaryKeySelective(teaOrder);
        } else if (successCount == 0) {
            log.error("全部断电失败");
            if (teaOrder.getServiceStatus() == 3 || teaOrder.getServiceStatus() == 5 || teaOrder.getServiceStatus() == 6) {
                teaOrder.setServiceStatus(7);
            } else {
                teaOrder.setServiceStatus(8);
            }
            TShareOrder tShareOrder = new TShareOrder();
            BeanUtil.copyProperties(teaOrder, tShareOrder);
            teaOrderMapper.updateById(tShareOrder);
            //teaOrderMapper.updateByPrimaryKeySelective(teaOrder);
        }
    }

    /**
     * 每小时获取tuya的Token并更新Token，防止Token过期
     *
     * @throws Exception
     */
    //@Scheduled(fixedDelay=100*100*1000)
    public void getAccessTokenTask() throws Exception {
        try {
 /*           if(StringUtils.isNotEmpty(TokenCache.getAccessTokenCache(tuyaClientId))) {
                return;
            }*/
            String getTokenPath = "/v1.0/token?grant_type=1";
            Object res = RequestSignUtils.execute(getTokenPath, "GET", "", new HashMap<>());
            Gson gson = new Gson();
            String str = gson.toJson(res);
            JSONObject resJson = JSONObject.parseObject(str);
            if (resJson.getBoolean("success")) {
                JSONObject resultJson = resJson.getJSONObject("result");
                TokenCache.setAccessTokenCache(tuyaClientId, resultJson.getString("access_token"));
                TokenCache.setRefreshTokenCache(tuyaClientId, resultJson.getString("refresh_token"));
                log.info("Runner -> get token success!");
            } else {
                log.error("Runner -> get token error! res={}", res);
            }
        } catch (Exception e) {
            log.error("Runner -> get token error! e：{}", e);
        }
    }

    /**
     * 处理未付款订单
     * 1、短信提醒(订单创建后，第6分钟)   2、超时自动取消(订单创建后，第16分钟)
     *
     * @param now
     * @param createTime
     */
    private void waitPayOrder(long now, long createTime, TeaOrderBo teaOrder) {
        long createTimeDiff = (now - createTime) / 1000 / 60;
        // 发送付款提醒短信
        if (createTimeDiff == 5 || createTimeDiff == 6) {
            log.error("{} 发送付款提醒短信：{}", new Date(), createTimeDiff);

        }

        // 自动取消订单
        if (createTimeDiff > 15) {
            log.error("{} 自动取消订单：{}", new Date(), createTimeDiff);
/*            teaOrder.setUpdateTime(new Date());
            teaOrder.setOrderStatus(OrderStatusEnum.CANCELLED.getIndex());
            TShareOrder tShareOrder = new TShareOrder();
            BeanUtil.copyProperties(teaOrder,tShareOrder);
            teaOrderMapper.updateById(tShareOrder);*/

            TShareOrder order = new TShareOrder();
            order.setId(teaOrder.getId());
            order.setServiceStatus(5);
            order.setOrderStatus(OrderStatusEnum.CANCELLED.getIndex());
            //order.setUpdateUserId(userId);
            order.setUpdateTime(new Date());
            teaOrderMapper.update(order, Wrappers.<TShareOrder>lambdaQuery()
                    .eq(TShareOrder::getId, teaOrder.getId()));


        }
    }

    public static String HMACSHA256(String data, String key) throws Exception {
        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
        SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
        sha256_HMAC.init(secret_key);
        byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }


    public static String sha256HMAC(String content, String secret) {
        Mac sha256HMAC = null;
        try {
            sha256HMAC = Mac.getInstance("HmacSHA256");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        SecretKey secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        try {
            assert sha256HMAC != null;
            sha256HMAC.init(secretKey);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        byte[] digest = sha256HMAC.doFinal(content.getBytes(StandardCharsets.UTF_8));
        return new HexBinaryAdapter().marshal(digest).toUpperCase();
    }

    @SneakyThrows
    public static void main(String[] args) {
/*        String getTokenPath = "/v1.0/token?grant_type=1";
        Object res = RequestSignUtils.execute(getTokenPath, "GET", "", new HashMap<>());
        Gson gson = new Gson();
        String str = gson.toJson(res);
        JSONObject resJson = JSONObject.parseObject(str);
        if(resJson.getBoolean("success")) {
            JSONObject resultJson = resJson.getJSONObject("result");
            System.out.println("access_token:"+resultJson.getString("access_token"));
        }*/
        //String teaServerEndTime = DateUtil.parseDate2String(teaOrder.getTeaServerEndTime(), "yyyy-MM-dd HH:mm");
        String teaServerEndTime = "2024-03-19 00:00";
        if(teaServerEndTime.contains("00:00")){

            teaServerEndTime = teaServerEndTime.substring(0,11)+"24:00";
            System.out.println(teaServerEndTime);
            //serverEndTime = DateUtils.parseStrint2Date(teaServerEndTime, "yyyy-MM-dd HH:mm").getTime();

        }
    }

    private void getAccessToken() {
        try {
            if (StringUtils.isNotEmpty(TokenCache.getAccessTokenCache(tuyaClientId))) {
                return;
            }
            // 调试中暂时注释

/*            String getTokenPath = "/v1.0/token?grant_type=1";
            Object res = RequestSignUtils.execute(getTokenPath, "GET", "", new HashMap<>());
            Gson gson = new Gson();
            String str = gson.toJson(res);
            JSONObject resJson = JSONObject.parseObject(str);
            if(resJson.getBoolean("success")) {
                JSONObject resultJson = resJson.getJSONObject("result");
                TokenCache.setAccessTokenCache(tuyaClientId, resultJson.getString("access_token"));
                TokenCache.setRefreshTokenCache(tuyaClientId, resultJson.getString("refresh_token"));
                log.info("Runner -> get token success!");
            } else {
                log.error("Runner -> get token error! res={}", res);
            }*/

        } catch (Exception e) {
            log.error("Runner -> get token error! e：{}", e);
        }
    }
}
